package com.mysen.sso.util;

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;

import org.apache.commons.fileupload.FileItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.mysen.exception.MaikeServiceException;
import com.mysen.util.IOUtils;

public class SFTPClient {

	private static final Logger LOGGER = LoggerFactory.getLogger(SFTPClient.class);

	private String host;
	private int port;
	private String username;
	private String password;
	private String ftppath;
	
	public SFTPClient(String host, int port, String username, String password, String ftppath) {
		this.host = host;
		this.port = port;
		this.username = username;
		this.password = password;
		this.ftppath = ftppath;
	}

	private ChannelSftp createFTPClient() throws Exception {
		JSch jsch = null;
        try {
        	jsch = new JSch();
        	LOGGER.debug("connecting...ftp server {}:{}", host, port); 
        	Session sshSession = jsch.getSession(username, host, port);
        	sshSession.setPassword(password);
	        sshSession.setConfig("StrictHostKeyChecking","no");
	        sshSession.connect(1500);
	        Channel channle = sshSession.openChannel("sftp");
	        channle.connect();
            LOGGER.debug("connect successful...ftp server {}:{}", host, port); 
            ChannelSftp channel = (ChannelSftp)channle;
            channel.cd(ftppath);
        	cd(channel, "ftp");
            return channel;
        } catch (JSchException e) {
			throw new MaikeServiceException("FtpClient create error!", e);
		}
	}
	
	public static void cd(ChannelSftp channel, String path) throws SftpException{
		String[] paths = path.split(File.separator);
        for(int i = 0; i < paths.length; i++) {
        	String p = paths[i];
        	if(StringUtils.hasText(p)) {
        		try {
        			channel.cd(p);
        		} catch (SftpException e) {
        			LOGGER.info("mkdir :{} at {}", p, channel.pwd());
        			channel.mkdir(channel.pwd()+File.separator+p);
        			channel.cd(p);
				}
        	}
        }
	}
	
	public void upload(String path, InputStream ins) throws SftpException {
		LOGGER.info("ftp upload start...");
		if(path.startsWith(File.separator)) {
			path = path.substring(1);
		}
		String pathName = path.substring(0, path.lastIndexOf(File.separator));
		String fileName = path.substring(path.lastIndexOf(File.separator) + 1);
		ChannelSftp channel = null;
        try{
            channel = createFTPClient();
            cd(channel, pathName);
            LOGGER.info("ftp upload file :{} !", channel.pwd()+File.separator+fileName);
            channel.put(ins, channel.pwd()+File.separator+fileName);
            LOGGER.info("ftp upload file success!");
        }catch (Exception e) {
        	if(channel != null){
        		throw new MaikeServiceException("ftp path:"+ channel.pwd()+" filename:"+fileName+" upload file failt!", e);
        	}
        	throw new MaikeServiceException("ftp connect error!", e);
        }finally{
            if(channel != null && channel.isConnected()){ 
            	channel.exit();
            }
            IOUtils.close(ins);
        }
	}
	
	public String upload(String path, FileItem item) {
		if(item == null)
		{
			throw new MaikeServiceException("ftp upload error cause: fileitem can not exist!!!");
		}
		try {
			String name = item.getName();
			LOGGER.info("file upload : {}", name);
			if(!name.contains(".")) {
				name = name + ".unkown";
			}
			if(path != null && !path.endsWith("/")) {
				path = path + File.separator + UUID.randomUUID().toString() + name.substring(name.lastIndexOf('.'));
			}
			this.upload(path, item.getInputStream());
			return path;
		} catch(MaikeServiceException e) {
			throw e;
		}catch (Exception e) {
			throw new MaikeServiceException("item can not get inputsteam!!!", e);
		} finally {
			item.delete();
		}
	}

	public void delete(String path) {
		if(path == null) {
			return;
		}
		if(path.startsWith(File.separator)) {
			path = path.substring(File.separator.length());
		}
		LOGGER.info("ftp delete start...");
		ChannelSftp channel = null;
        try{
            channel = createFTPClient();
        	if(path.endsWith(File.separator)) {
        		channel.rmdir(path);
        	} else {
        		String p = path.substring(0, path.lastIndexOf(File.separator));
        		channel.cd(p);
        		String f = path.substring(path.lastIndexOf(File.separator) + 1);
        	    channel.rm(f);
        	}
            LOGGER.info("ftp delete file success!");
        }catch (Exception e) {
        	LOGGER.info("ftp delete file:{} not exist", path);
        }finally{
            if(channel != null && channel.isConnected()){ 
                channel.exit();
            }
        }
	}
	
	public int transfer(String path, OutputStream ous) {
		if(path == null) {
    		throw new MaikeServiceException("this not is a file!");
		}
		if(path.startsWith(File.separator)) {
			path = path.substring(File.separator.length());
		}
		LOGGER.info("ftp transfer start...");
		ChannelSftp channel = null;
		InputStream ins = null;
		try{
            channel = createFTPClient();
        	if(path.endsWith(File.separator)) {
        		throw new MaikeServiceException("this not is a file!");
        	} else {
        		String p = path.substring(0, path.lastIndexOf(File.separator));
        		channel.cd(p);
        		String f = path.substring(path.lastIndexOf(File.separator) + 1);
        	    ins = channel.get(f);
        	    return StreamUtils.copy(ins, ous);
        	}
        }catch (Exception e) {
        	throw new MaikeServiceException("ftp transfer file "+path+" not exist");
        }finally{
            if(channel != null && channel.isConnected()){ 
                channel.exit();
            }
            IOUtils.close(ins);
        }
	}
}
